import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  HttpStatus,
  Param,
  ParseUUIDPipe,
  Patch,
  Post,
  Put,
  Query,
  UseGuards,
  ForbiddenException,
} from '@nestjs/common';
import {
  ApiBearerAuth,
  ApiOperation,
  ApiParam,
  ApiQuery,
  ApiResponse,
  ApiTags,
} from '@nestjs/swagger';
import { TasksService } from './tasks.service';
import {
  CreateFromTemplateDto,
  CreateTaskDto,
  PaginatedTaskResponseDto,
  QueryTaskDto,
  TaskResponseDto,
  UpdateTaskDto,
} from './dto';
import { Task } from './entities/task.entity';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles } from '../auth/decorators/roles.decorator';
import { TaskStatus, UserRole } from '../common';
import { CurrentUser } from '../auth/decorators/current-user.decorator';
import { JwtPayload } from '../auth/interfaces/jwt-payload.interface';
import { TaskEditGuard } from './guards';
import { PaginatedResponseDto, PaginationMetaDto } from '../common/dto/pagination.dto';

@ApiTags('Task')
@Controller('tasks')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class TasksController {
  constructor(private readonly tasksService: TasksService) {}

  @Post()
  @UseGuards(RolesGuard)
  @Roles(UserRole.ADMIN)
  @ApiOperation({ summary: '创建一个新任务' })
  @ApiResponse({
    status: HttpStatus.CREATED,
    description: 'Task created successfully.',
    type: TaskResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'Invalid input data.',
  })
  @ApiResponse({
    status: HttpStatus.CONFLICT,
    description: 'Device is not assigned to the specified user.',
  })
  async create(@Body() createTaskDto: CreateTaskDto): Promise<TaskResponseDto> {
    const task = await this.tasksService.create(createTaskDto);
    return this.tasksService.mapTaskToDto(task);
  }

  @Get()
  @UseGuards(RolesGuard)
  @Roles(UserRole.ADMIN)
  @ApiOperation({ summary: '查询任务列表' })
  @ApiQuery({ name: 'page', required: false, type: Number, description: '页码 (从1开始)' })
  @ApiQuery({ name: 'pageSize', required: false, type: Number, description: '每页数量' })
  @ApiQuery({ name: 'assignedUserId', required: false, type: String })
  @ApiQuery({ name: 'status', required: false, enum: TaskStatus })
  @ApiQuery({ name: 'title', required: false, type: String })
  @ApiQuery({ name: 'parentTaskId', required: false, type: String })
  @ApiQuery({ name: 'taskTemplateId', required: false, type: String })
  @ApiQuery({
    name: 'type',
    required: false,
    description: '任务类型 (逗号分隔, 例如: "single,global")',
    type: String,
  })
  @ApiQuery({
    name: 'includeDeleted',
    required: false,
    type: Boolean,
    description: '是否包含已删除任务 (默认: false)',
  })
  @ApiQuery({
    name: 'sortBy',
    required: false,
    description: '排序字段 (默认: createdAt)',
    enum: ['createdAt', 'dueTime', 'title'],
  })
  @ApiQuery({
    name: 'sortDirection',
    required: false,
    description: '排序方向 (默认: DESC)',
    enum: ['ASC', 'DESC'],
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '返回任务列表 (默认按创建时间降序排序)',
    type: PaginatedTaskResponseDto,
  })
  async findAll(
    @Query() queryDto: QueryTaskDto,
    @Query('assignedUserId') assignedUserId?: string,
    @Query('includeDeleted') includeDeleted?: boolean,
  ): Promise<PaginatedTaskResponseDto> {
    const paginatedResponse = await this.tasksService.findAllPaginated({
      ...queryDto,
      assignedUserId,
      includeDeleted,
    });

    return this.tasksService.mapPaginatedResponse(paginatedResponse as PaginatedResponseDto<Task>);
  }

  // Make sure "/task/me" API is ahead of "/task/:taskId" to avoid conflict
  @Get('me')
  @UseGuards(JwtAuthGuard)
  @ApiOperation({ summary: '获取当前用户的任务列表（包括全局任务，不包括已删除任务）' })
  @ApiQuery({ name: 'page', required: false, description: '页码 (从1开始)', type: Number })
  @ApiQuery({ name: 'pageSize', required: false, description: '每页数量', type: Number })
  @ApiQuery({ name: 'status', required: false, description: '任务状态', enum: TaskStatus })
  @ApiQuery({ name: 'title', required: false, description: '任务标题 (模糊匹配)', type: String })
  @ApiQuery({ name: 'parentTaskId', required: false, description: '父任务ID', type: String })
  @ApiQuery({ name: 'taskTemplateId', required: false, description: '任务模板ID', type: String })
  @ApiQuery({
    name: 'type',
    required: false,
    description: '任务类型 (逗号分隔, 例如: "single,global")',
    type: String,
  })
  @ApiQuery({
    name: 'sortBy',
    required: false,
    description: '排序字段 (默认: createdAt)',
    enum: ['createdAt', 'dueTime', 'title'],
  })
  @ApiQuery({
    name: 'sortDirection',
    required: false,
    description: '排序方向 (默认: DESC)',
    enum: ['ASC', 'DESC'],
  })
  @ApiResponse({
    status: HttpStatus.OK,
    description: '返回当前用户的任务列表（不包括已删除任务）',
    type: PaginatedTaskResponseDto,
  })
  async findMyTasks(
    @CurrentUser() user: JwtPayload,
    @Query() queryDto: QueryTaskDto,
  ): Promise<PaginatedTaskResponseDto> {
    // Check if user is admin, if so, throw ForbiddenException
    if (user.role === UserRole.ADMIN) {
      throw new ForbiddenException('Admin users cannot access /tasks/me endpoint');
    }

    const paginatedTasks = await this.tasksService.findTasksForUser(user.userId, queryDto);
    return this.tasksService.mapPaginatedResponse(paginatedTasks as PaginatedResponseDto<Task>);
  }

  @Get(':taskId')
  @UseGuards(RolesGuard)
  @Roles(UserRole.ADMIN)
  @ApiOperation({ summary: '获取任务详情' })
  @ApiParam({ name: 'taskId', type: String, format: 'uuid' })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'Task details.',
    type: TaskResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: 'Task not found.',
  })
  async findOne(@Param('taskId', ParseUUIDPipe) id: string): Promise<TaskResponseDto> {
    const task = await this.tasksService.findOne(id);
    return this.tasksService.mapTaskToDto(task);
  }

  @Put(':taskId')
  @UseGuards(TaskEditGuard)
  @ApiOperation({ summary: '更新已有任务' })
  @ApiParam({ name: 'taskId', type: String, format: 'uuid' })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'Task updated successfully.',
    type: TaskResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.BAD_REQUEST,
    description: 'Invalid input data.',
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: 'Task not found.',
  })
  @ApiResponse({
    status: HttpStatus.FORBIDDEN,
    description: 'Regular users cannot edit global tasks or tasks not assigned to them.',
  })
  async update(
    @Param('taskId', ParseUUIDPipe) id: string,
    @Body() updateTaskDto: UpdateTaskDto,
  ): Promise<TaskResponseDto> {
    const task = await this.tasksService.update(id, updateTaskDto);
    return this.tasksService.mapTaskToDto(task);
  }

  @Patch(':taskId/complete')
  @UseGuards(RolesGuard, TaskEditGuard)
  @Roles(UserRole.USER)
  @ApiOperation({ summary: '标记任务为已完成' })
  @ApiParam({ name: 'taskId', type: String, format: 'uuid' })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'Task marked as completed.',
    type: TaskResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: 'Task not found.',
  })
  @ApiResponse({
    status: HttpStatus.FORBIDDEN,
    description: 'Regular users cannot complete global tasks or tasks not assigned to them.',
  })
  async markAsCompleted(@Param('taskId', ParseUUIDPipe) id: string): Promise<TaskResponseDto> {
    const task = await this.tasksService.markAsCompleted(id);
    return this.tasksService.mapTaskToDto(task);
  }

  @Patch(':taskId/not-started')
  @UseGuards(RolesGuard, TaskEditGuard)
  @Roles(UserRole.USER)
  @ApiOperation({ summary: '将任务标记为未开始（从已完成状态恢复）' })
  @ApiParam({ name: 'taskId', type: String, format: 'uuid' })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'Task marked as not started.',
    type: TaskResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: 'Task not found.',
  })
  @ApiResponse({
    status: HttpStatus.FORBIDDEN,
    description: 'Regular users cannot modify global tasks or tasks not assigned to them.',
  })
  async markAsNotStarted(@Param('taskId', ParseUUIDPipe) id: string): Promise<TaskResponseDto> {
    const task = await this.tasksService.markAsNotStarted(id);
    return this.tasksService.mapTaskToDto(task);
  }

  @Delete(':taskId')
  @UseGuards(RolesGuard)
  @Roles(UserRole.ADMIN)
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: '删除任务（软删除）' })
  @ApiParam({ name: 'taskId', type: String, format: 'uuid' })
  @ApiResponse({
    status: HttpStatus.NO_CONTENT,
    description: 'Task removed successfully.',
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: 'Task not found.',
  })
  async remove(@Param('taskId', ParseUUIDPipe) id: string): Promise<void> {
    return this.tasksService.remove(id);
  }

  @Patch(':taskId/remove')
  @UseGuards(RolesGuard, TaskEditGuard)
  @Roles(UserRole.USER)
  @ApiOperation({ summary: '标记任务为已移除（仅用户可操作）' })
  @ApiParam({ name: 'taskId', type: String, format: 'uuid' })
  @ApiResponse({
    status: HttpStatus.OK,
    description: 'Task marked as removed.',
    type: TaskResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: 'Task not found.',
  })
  @ApiResponse({
    status: HttpStatus.FORBIDDEN,
    description: 'Regular users cannot remove global tasks or tasks not assigned to them.',
  })
  async markAsRemoved(@Param('taskId', ParseUUIDPipe) id: string): Promise<TaskResponseDto> {
    const task = await this.tasksService.markAsRemoved(id);
    return this.tasksService.mapTaskToDto(task);
  }

  @Post('from-template/:templateId')
  @UseGuards(RolesGuard)
  @Roles(UserRole.ADMIN)
  @ApiOperation({ summary: '从模板创建任务' })
  @ApiParam({ name: 'templateId', type: String, format: 'uuid' })
  @ApiResponse({
    status: HttpStatus.CREATED,
    description: '从模板创建任务成功',
    type: TaskResponseDto,
  })
  @ApiResponse({
    status: HttpStatus.NOT_FOUND,
    description: '模板未找到',
  })
  async createFromTemplate(
    @Param('templateId', ParseUUIDPipe) templateId: string,
    @Body() createFromTemplateDto: CreateFromTemplateDto,
  ): Promise<TaskResponseDto> {
    const task = await this.tasksService.createFromTemplate(templateId, createFromTemplateDto);
    return this.tasksService.mapTaskToDto(task);
  }
}
